1 /*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7 /*
8 * Source:
9 * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/extra/AtomicDoubleArray.java?revision=1.5
10 * (Modified to adapt to guava coding conventions and
11 * to use AtomicLongArray instead of sun.misc.Unsafe)
12 */
13
14 package com.google.common.util.concurrent;
15
16 import static java.lang.Double.doubleToRawLongBits;
17 import static java.lang.Double.longBitsToDouble;
18
19 import java.util.concurrent.atomic.AtomicLongArray;
20
21 /**
22 * A {@code double} array in which elements may be updated atomically.
23 * See the {@link java.util.concurrent.atomic} package specification
24 * for description of the properties of atomic variables.
25 *
26 * <p><a name="bitEquals">This class compares primitive {@code double}
27 * values in methods such as {@link #compareAndSet} by comparing their
28 * bitwise representation using {@link Double#doubleToRawLongBits},
29 * which differs from both the primitive double {@code ==} operator
30 * and from {@link Double#equals}, as if implemented by:
31 * <pre> {@code
32 * static boolean bitEquals(double x, double y) {
33 * long xBits = Double.doubleToRawLongBits(x);
34 * long yBits = Double.doubleToRawLongBits(y);
35 * return xBits == yBits;
36 * }}</pre>
37 *
38 * @author Doug Lea
39 * @author Martin Buchholz
40 * @since 11.0
41 */
42 public class AtomicDoubleArray implements java.io.Serializable {
43 private static final long serialVersionUID = 0L;
44
45 // Making this non-final is the lesser evil according to Effective
46 // Java 2nd Edition Item 76: Write readObject methods defensively.
47 private transient AtomicLongArray longs;
48
49 /**
50 * Creates a new {@code AtomicDoubleArray} of the given length,
51 * with all elements initially zero.
52 *
53 * @param length the length of the array
54 */
55 public AtomicDoubleArray(int length) {
56 this.longs = new AtomicLongArray(length);
57 }
58
59 /**
60 * Creates a new {@code AtomicDoubleArray} with the same length
61 * as, and all elements copied from, the given array.
62 *
63 * @param array the array to copy elements from
64 * @throws NullPointerException if array is null
65 */
66 public AtomicDoubleArray(double[] array) {
67 final int len = array.length;
68 long[] longArray = new long[len];
69 for (int i = 0; i < len; i++) {
70 longArray[i] = doubleToRawLongBits(array[i]);
71 }
72 this.longs = new AtomicLongArray(longArray);
73 }
74
75 /**
76 * Returns the length of the array.
77 *
78 * @return the length of the array
79 */
80 public final int length() {
81 return longs.length();
82 }
83
84 /**
85 * Gets the current value at position {@code i}.
86 *
87 * @param i the index
88 * @return the current value
89 */
90 public final double get(int i) {
91 return longBitsToDouble(longs.get(i));
92 }
93
94 /**
95 * Sets the element at position {@code i} to the given value.
96 *
97 * @param i the index
98 * @param newValue the new value
99 */
100 public final void set(int i, double newValue) {
101 long next = doubleToRawLongBits(newValue);
102 longs.set(i, next);
103 }
104
105 /**
106 * Eventually sets the element at position {@code i} to the given value.
107 *
108 * @param i the index
109 * @param newValue the new value
110 */
111 public final void lazySet(int i, double newValue) {
112 set(i, newValue);
113 // TODO(user): replace with code below when jdk5 support is dropped.
114 // long next = doubleToRawLongBits(newValue);
115 // longs.lazySet(i, next);
116 }
117
118 /**
119 * Atomically sets the element at position {@code i} to the given value
120 * and returns the old value.
121 *
122 * @param i the index
123 * @param newValue the new value
124 * @return the previous value
125 */
126 public final double getAndSet(int i, double newValue) {
127 long next = doubleToRawLongBits(newValue);
128 return longBitsToDouble(longs.getAndSet(i, next));
129 }
130
131 /**
132 * Atomically sets the element at position {@code i} to the given
133 * updated value
134 * if the current value is <a href="#bitEquals">bitwise equal</a>
135 * to the expected value.
136 *
137 * @param i the index
138 * @param expect the expected value
139 * @param update the new value
140 * @return true if successful. False return indicates that
141 * the actual value was not equal to the expected value.
142 */
143 public final boolean compareAndSet(int i, double expect, double update) {
144 return longs.compareAndSet(i,
145 doubleToRawLongBits(expect),
146 doubleToRawLongBits(update));
147 }
148
149 /**
150 * Atomically sets the element at position {@code i} to the given
151 * updated value
152 * if the current value is <a href="#bitEquals">bitwise equal</a>
153 * to the expected value.
154 *
155 * <p>May <a
156 * href="http://download.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html#Spurious">
157 * fail spuriously</a>
158 * and does not provide ordering guarantees, so is only rarely an
159 * appropriate alternative to {@code compareAndSet}.
160 *
161 * @param i the index
162 * @param expect the expected value
163 * @param update the new value
164 * @return true if successful
165 */
166 public final boolean weakCompareAndSet(int i, double expect, double update) {
167 return longs.weakCompareAndSet(i,
168 doubleToRawLongBits(expect),
169 doubleToRawLongBits(update));
170 }
171
172 /**
173 * Atomically adds the given value to the element at index {@code i}.
174 *
175 * @param i the index
176 * @param delta the value to add
177 * @return the previous value
178 */
179 public final double getAndAdd(int i, double delta) {
180 while (true) {
181 long current = longs.get(i);
182 double currentVal = longBitsToDouble(current);
183 double nextVal = currentVal + delta;
184 long next = doubleToRawLongBits(nextVal);
185 if (longs.compareAndSet(i, current, next)) {
186 return currentVal;
187 }
188 }
189 }
190
191 /**
192 * Atomically adds the given value to the element at index {@code i}.
193 *
194 * @param i the index
195 * @param delta the value to add
196 * @return the updated value
197 */
198 public double addAndGet(int i, double delta) {
199 while (true) {
200 long current = longs.get(i);
201 double currentVal = longBitsToDouble(current);
202 double nextVal = currentVal + delta;
203 long next = doubleToRawLongBits(nextVal);
204 if (longs.compareAndSet(i, current, next)) {
205 return nextVal;
206 }
207 }
208 }
209
210 /**
211 * Returns the String representation of the current values of array.
212 * @return the String representation of the current values of array
213 */
214 public String toString() {
215 int iMax = length() - 1;
216 if (iMax == -1) {
217 return "[]";
218 }
219
220 // Double.toString(Math.PI).length() == 17
221 StringBuilder b = new StringBuilder((17 + 2) * (iMax + 1));
222 b.append('[');
223 for (int i = 0;; i++) {
224 b.append(longBitsToDouble(longs.get(i)));
225 if (i == iMax) {
226 return b.append(']').toString();
227 }
228 b.append(',').append(' ');
229 }
230 }
231
232 /**
233 * Saves the state to a stream (that is, serializes it).
234 *
235 * @serialData The length of the array is emitted (int), followed by all
236 * of its elements (each a {@code double}) in the proper order.
237 */
238 private void writeObject(java.io.ObjectOutputStream s)
239 throws java.io.IOException {
240 s.defaultWriteObject();
241
242 // Write out array length
243 int length = length();
244 s.writeInt(length);
245
246 // Write out all elements in the proper order.
247 for (int i = 0; i < length; i++) {
248 s.writeDouble(get(i));
249 }
250 }
251
252 /**
253 * Reconstitutes the instance from a stream (that is, deserializes it).
254 */
255 private void readObject(java.io.ObjectInputStream s)
256 throws java.io.IOException, ClassNotFoundException {
257 s.defaultReadObject();
258
259 // Read in array length and allocate array
260 int length = s.readInt();
261 this.longs = new AtomicLongArray(length);
262
263 // Read in all elements in the proper order.
264 for (int i = 0; i < length; i++) {
265 set(i, s.readDouble());
266 }
267 }
268 }